package com.example.esdemo.es.services;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.core.utils.Beans;
import com.example.esdemo.es.dao.PostRepository;
import com.example.esdemo.es.entities.EsPost;
import com.example.esdemo.forms.PostSearchForm;
import com.example.esdemo.rabbitmq.ESMqMessage;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Cary
 * @date 2022/6/21
 */
@Service
@Slf4j
public class EsPostService {
    @Autowired
    private PostRepository postRepository;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    public void createOrUpdateIndex(ESMqMessage message) {
        postRepository.save(message.getEsPost());
        log.info("[es]索引更新成功：{}", message);
    }

    public void removeIndex(ESMqMessage message) {
        EsPost esPost = message.getEsPost();
        postRepository.deleteById(esPost.getId());
        log.info("[es]索引删除成功：{}", message);
    }

    public List<EsPost> list() {
        List<EsPost> list = new ArrayList<>();
        Iterable<EsPost> iterable = postRepository.findAll();
        iterable.forEach(list::add);
        return list;
    }

    public IPage<EsPost> search(PostSearchForm form) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        /*
         * BoolQuery( ) 多条件查询
         *
         *  must 相当于 and
         *  must not 相当于 not
         *  should 相当于  or
         */
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        if (Beans.strNotEmpty(form.getKw())) {
            /*
             * termQuery("key", obj) 完全匹配
             * termsQuery("key", obj1, obj2..)   一次匹配多个值
             * matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
             * multiMatchQuery("text", "field1", "field2"..);  匹配多个字段, field有通配符忒行
             * matchAllQuery();         匹配所有文件
             * rangeQuery("key");   范围查询
             * moreLikeThisQuery("key", obj)  模糊查询
             * matchAllQuery()  全查询
             */
            bool.should(QueryBuilders.matchPhraseQuery("title", form.getKw()));
            bool.should(QueryBuilders.matchPhraseQuery("content", form.getKw()));

            /*
             * 高亮
             * ##pre_tags：替换前置标签
             * ##post_tags:替换后置标签
             * ##fragment_size:设置要显示的文本长度，默认100
             * ##number_of_fragments：设置指定的文本片段个数
             * ##no_match_size：设置那些query没有匹配到的doc,你的高亮可以显示前缀多少个字符
             */
            builder.withHighlightFields(new HighlightBuilder.Field("title").numOfFragments(0),
                    new HighlightBuilder.Field("content").numOfFragments(0));
            builder.withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>"));
        }
        builder.withQuery(bool);

        // 排序 按创建时间倒序
        FieldSortBuilder createTimeSortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        // 相关性得分 (_score) 默认倒序
        ScoreSortBuilder scoreSortBuilder = new ScoreSortBuilder();
        builder.withSorts(createTimeSortBuilder);
        builder.withSorts(scoreSortBuilder);

        // 分页
        PageRequest pageRequest = PageRequest.of(form.getPage() - 1, form.getPageSize());
        builder.withPageable(pageRequest);

        // 查询
        SearchHits<EsPost> hits = elasticsearchRestTemplate.search(builder.build(), EsPost.class);

        // 高亮内容替换
        List<EsPost> list = new ArrayList<>();
        hits.forEach(item -> {
            EsPost esPost = item.getContent();
            // 获取高亮信息
            List<String> title = item.getHighlightField("title");
            List<String> content = item.getHighlightField("content");
            // 替换原来字段内容
            if (title.size() > 0) {
                esPost.setTitle(title.get(0));
            }
            if (content.size() > 0) {
                esPost.setContent(content.get(0));
            }
            list.add(esPost);
        });

        IPage<EsPost> page = new Page<>(form.getPage(), form.getPageSize(), hits.getTotalHits());
        page.setRecords(list);
        return page;
    }
}
